import type { PageParams, PageResponse, Result } from "@/apis/types";
import { reactive, ref, toRefs, type Ref } from "vue";

export interface OptionsObject {
  // 是否手动发起请求
  manual?: boolean;
  // 是否分页
  isPage?: boolean;
  // 提示成功信息
  showSuccess?: boolean;
  // 是否返回上一页
  isBack?: boolean;
  // 显示loading
  showLoading?: boolean;
}

export interface queriseType<T> {
  data: Ref<HasResponse<T>> | null;
  msg: string;
  loading: boolean;
}

type HasResponse<T> = T extends PageResponse ? any[] : T;

export type Service<T, P extends any[]> = (
  ...args: P
) => Promise<Result<HasResponse<T>>>;

export const useRequest = <T, P extends any[]>(
  execute: [service: Service<T, P>, ...params: P],
  options?: OptionsObject
) => {
  const [service, params] = execute;

  const querise = reactive<queriseType<T>>({
    data: null,
    msg: "",
    loading: false,
  });

  // 普通请求
  const query = async () => {
    try {
      if (options?.showLoading && uni.showLoading) {
        uni.showLoading({ title: "加载中" });
      }
      // @ts-ignore 暂时不知道如何解决 ts2345 问题
      const { data, msg } = await service(params);
      querise.data = data;
      querise.msg = msg;
      if (options?.isBack) {
        uni.navigateBack({ delta: 1 });
      }
      if (options?.showSuccess) {
        uni.showToast({ title: msg || ''});
      }
      if (options?.showLoading) {
        uni.hideLoading();
      }
    } catch (error) {
      if (options?.showLoading && uni.hideLoading) {
        uni.hideLoading();
      }
      throw Error(`${JSON.stringify(error)}`);
    }
  };

  const pageParams = reactive<Required<PageParams>>({
    pageSize: 20,
    pageNum: 0,
  });
  const isOver = ref(false);

  // 分页请求
  const loadMore = async () => {
    try {
      if (isOver.value) return;
      if (options?.showLoading && uni.showLoading) {
        uni.showLoading({ title: "加载中" });
      }
      pageParams.pageNum += 1;
      // @ts-ignore 暂时不知道如何解决 ts2345 问题
      const { rows, msg, total }: any = await service(params, pageParams);
      if (options?.showLoading && uni.hideLoading) {
        uni.hideLoading();
      }

      if (querise.data) {
        // @ts-ignore
        querise.data = [...querise.data, ...rows];
      } else {
        querise.data = rows;
      }
      // @ts-ignore
      if (querise.data?.length === total) isOver.value = true;
      querise.msg = msg;
    } catch (error) {
      if (options?.showLoading && uni.hideLoading) {
        uni.hideLoading();
      }
      throw Error(`${JSON.stringify(error)}`);
    }
  };

  const run = async () => {
    querise.loading = true;
    options?.isPage ? await loadMore() : await query();
    querise.loading = false;
  };

  if (!options?.manual) run();

  return { run, ...toRefs(querise), isOver };
};
